using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Sensor.SerialPorts.Enums;
using Sensor.UI.Models;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using Sensor.UI.PointClouds;

namespace Sensor.UI.ViewModels;

/// <summary>
/// 主视图模型，负责管理整个应用程序的状态和交互
/// </summary>
public partial class MainViewModel : ViewModelBase
{
    #region 私有字段

    /// <summary>
    /// 取消令牌源，用于取消异步操作
    /// </summary>
    private readonly CancellationTokenSource _cancellationTokenSource = new();

    #endregion

    #region 公共属性

    /// <summary>
    /// 串口配置视图模型
    /// </summary>
    [ObservableProperty]
    private SerialPortConfigViewModel _serialPortConfig;

    /// <summary>
    /// 串口会话视图模型
    /// </summary>
    [ObservableProperty]
    private SerialPortSessionViewModel _serialPortSession;

    /// <summary>
    /// 系统日志视图模型
    /// </summary>
    [ObservableProperty]
    private SystemLogViewModel _systemLog;

    /// <summary>
    /// 点云视图模型
    /// </summary>
    [ObservableProperty]
    private PointCloudViewModel _pointCloud;

    /// <summary>
    /// 获取或设置连接按钮文本
    /// </summary>
    [ObservableProperty]
    private string _connectButtonText = "连接";

    /// <summary>
    /// 获取或设置是否已连接
    /// </summary>
    [ObservableProperty]
    private bool _isConnected;

    #endregion

    #region 构造函数

    /// <summary>
    /// 初始化 MainViewModel 类的新实例
    /// </summary>
    public MainViewModel()
    {
        SerialPortConfig = new SerialPortConfigViewModel();
        SerialPortSession = new SerialPortSessionViewModel();
        SystemLog = new SystemLogViewModel();
        PointCloud = new PointCloudViewModel();
        // 订阅串口会话事件
        SubscribeToSerialPortEvents();

        // 如果有可用串口，默认选择第一个
        if (SerialPortConfig.Port.Count > 0)
        {
            SerialPortSession.Port = SerialPortConfig.Port[0];
        }
    }

    #endregion

    #region 公共方法

    /// <summary>
    /// 订阅串口会话事件
    /// </summary>
    private void SubscribeToSerialPortEvents()
    {
        SerialPortSession.ValidFrameReceived += OnValidFrameReceived;
        SerialPortSession.ErrorOccurred += OnErrorOccurred;
    }

    /// <summary>
    /// 取消订阅串口会话事件
    /// </summary>
    private void UnsubscribeFromSerialPortEvents()
    {
        SerialPortSession.ValidFrameReceived -= OnValidFrameReceived;
        SerialPortSession.ErrorOccurred -= OnErrorOccurred;
    }

    /// <summary>
    /// 连接串口
    /// </summary>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>表示异步操作的任务</returns>
    private async Task ConnectAsync(CancellationToken cancellationToken = default)
    {
        if (string.IsNullOrEmpty(SerialPortSession.Port))
        {
            SystemLog.AddLog("请选择串口");
            return;
        }

        try
        {
            SystemLog.AddLog($"正在连接串口 {SerialPortSession.Port}...");
            await SerialPortSession.OpenAsync(cancellationToken).ConfigureAwait(false);
            
            IsConnected = SerialPortSession.IsOpen;
            ConnectButtonText = "断开";
            SystemLog.AddLog($"串口 {SerialPortSession.Port} 连接成功");
        }
        catch (Exception ex)
        {
            SystemLog.AddLog($"连接串口失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 断开串口连接
    /// </summary>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>表示异步操作的任务</returns>
    private async Task DisconnectAsync(CancellationToken cancellationToken = default)
    {
        try
        {
            SystemLog.AddLog("正在断开串口连接...");
            await SerialPortSession.CloseAsync(cancellationToken).ConfigureAwait(false);
            
            IsConnected = SerialPortSession.IsOpen;
            ConnectButtonText = "连接";
            SystemLog.AddLog("串口连接已断开");
        }
        catch (Exception ex)
        {
            SystemLog.AddLog($"断开串口连接失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 处理接收到的有效数据帧
    /// </summary>
    /// <param name="frameText">原始帧文本</param>
    /// <param name="sensorInfo">解析后的传感器信息</param>
    private async void OnValidFrameReceived(string frameText, SensorInfo sensorInfo)
    {
        ArgumentNullException.ThrowIfNull(frameText);
        ArgumentNullException.ThrowIfNull(sensorInfo);

        try
        {
            // 使用异步方式更新点云数据，支持高并发有序执行
            await PointCloud.UpdatePointCloudAsync(sensorInfo).ConfigureAwait(false);
            
            // 在UI线程上更新日志
            SystemLog.AddLog($"接收到传感器数据: {frameText}");

        }
        catch (OperationCanceledException)
        {
            // 操作被取消，这是预期的行为，不需要记录错误
        }
        catch (Exception ex)
        {
            // 在UI线程上记录错误
            await App.Current.Dispatcher.InvokeAsync(() =>
            {
                SystemLog.AddLog($"更新点云数据失败: {ex.Message}");
            });
        }
    }

    /// <summary>
    /// 处理串口错误
    /// </summary>
    /// <param name="errorMessage">错误消息</param>
    private void OnErrorOccurred(string errorMessage)
    {
        ArgumentNullException.ThrowIfNull(errorMessage);
        SystemLog.AddLog($"错误: {errorMessage}");
        
        // 如果发生错误，更新连接状态
        if (IsConnected)
        {
            IsConnected = false;
            ConnectButtonText = "连接";
        }
    }

    #endregion

    #region 命令

    /// <summary>
    /// 连接/断开串口命令
    /// </summary>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>表示异步操作的任务</returns>
    [RelayCommand]
    private async Task ConnectDisconnectAsync(CancellationToken cancellationToken = default)
    {
        try
        {
            if (IsConnected)
            {
                // 断开连接
                await DisconnectAsync(cancellationToken).ConfigureAwait(false);
            }
            else
            {
                // 建立连接
                await ConnectAsync(cancellationToken).ConfigureAwait(false);
            }
        }
        catch (Exception ex)
        {
            SystemLog.AddLog($"操作失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 刷新串口列表命令
    /// </summary>
    [RelayCommand]
    private void RefreshPorts()
    {
        SerialPortConfig.RefreshPortList();
        SystemLog.AddLog("串口列表已刷新");
    }


    /// <summary>
    /// 清空日志命令
    /// </summary>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>表示异步操作的任务</returns>
    [RelayCommand]
    private async Task ClearLogAsync(CancellationToken cancellationToken = default)
    {
        await SystemLog.ClearLogsAsync(cancellationToken).ConfigureAwait(false);
    }

    /// <summary>
    /// 打开仓库链接命令
    /// </summary>
    [RelayCommand]
    private static void OpenRepoLink()
    {
        System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
        {
            FileName = "https://github.com/wuzxc1230123",
            UseShellExecute = true
        });
    }

    /// <summary>
    /// 最小化窗口命令
    /// </summary>
    /// <param name="parameter">窗口对象</param>
    [RelayCommand]
    private static void WindowMinimize(object parameter)
    {
        if (parameter is System.Windows.Window window)
        {
            window.WindowState = System.Windows.WindowState.Minimized;
        }
    }

    /// <summary>
    /// 关闭窗口命令
    /// </summary>
    /// <param name="parameter">窗口对象</param>
    [RelayCommand]
    private static void WindowClose(object parameter)
    {
        if (parameter is System.Windows.Window window)
        {
            window.Close();
        }
    }
    #endregion
}

